#include "SPI_Flash.h"
#include "string.h"


extern uint32_t SystemCoreClock;
__IO uint8_t flashmode_cf = 1;	//0代表4字节模式，1代表3字节模式

uint32_t maxWaitCnt = 1200000;	//防止死循环的



/*
在SPI CS = H 后，延时
防止SPI内部无法识别读写指令结束
*/
void delayAfterSPI_CS_H(void)
{
	uint8_t i;
	uint8_t cntMax;
	
	//理论上相当于延时0.5uS
	if (SystemCoreClock == 120000000)
	{
		cntMax = 12;
	}
	else
	{
		cntMax = 1;
	}
	
	
	for(i=0;i<cntMax;i++)
	{
		__NOP();
	}
}

void SPI1_Configuration(void)
{
		spi_parameter_struct spi_init_struct;
	
    rcu_periph_clock_enable(RCU_GPIOB);
//    rcu_periph_clock_enable(RCU_AF);
    rcu_periph_clock_enable(RCU_SPI1);

	  /* SPI1 config:SCK/PB13, MISO/PB14, MOSI/PB15 CS/PB12*/
    gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_13 | GPIO_PIN_15);
    gpio_init(GPIOB, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_14);
		gpio_init(GPIOB, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_12);
	
		FLASH_CS_H;

	
    /* deinitilize SPI and the parameters */
    spi_i2s_deinit(SPI1);
    spi_struct_para_init(&spi_init_struct);

    /* SPI0 parameter config */
    spi_init_struct.trans_mode           = SPI_TRANSMODE_FULLDUPLEX;
    spi_init_struct.device_mode          = SPI_MASTER;
    spi_init_struct.frame_size           = SPI_FRAMESIZE_8BIT;
    spi_init_struct.clock_polarity_phase = SPI_CK_PL_HIGH_PH_2EDGE;
    spi_init_struct.nss                  = SPI_NSS_SOFT;
		
		
		if (SystemCoreClock == 120000000)
		{	//因为CPU规定的最高SPI频率为30M，所以/4
			spi_init_struct.prescale             = SPI_PSC_4;
		}
		else
		{
			spi_init_struct.prescale             = SPI_PSC_2;
		}
		
		if (SystemCoreClock == 120000000)
		{
			maxWaitCnt = 600000;		//实测6000是临界值，5000时会报错
		}
		else
		{
			maxWaitCnt = 100000;		//实测1000是临界值
		}



    spi_init_struct.endian               = SPI_ENDIAN_MSB;
		
    spi_init(SPI1, &spi_init_struct);
    /* set crc polynomial */
//    spi_crc_polynomial_set(SPI0,7);
	  spi_enable(SPI1);
}


//void SPI0_Configuration(void)
//{
//		spi_parameter_struct spi_init_struct;
//	
//    rcu_periph_clock_enable(RCU_GPIOA);
////    rcu_periph_clock_enable(RCU_AF);
//    rcu_periph_clock_enable(RCU_SPI0);

//	    /* SPI0 GPIO config:SCK/PA5, MISO/PA6, MOSI/PA7 CS/PA4*/
//    gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_5 | GPIO_PIN_7);
//    gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_6);
//	
//		gpio_init(GPIOA, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_4);
////		GPIO_BOP(GPIOA) = GPIO_PIN_4;
//		FLASH_CS_H;
//	
//	  
//    /* deinitilize SPI and the parameters */
//    spi_i2s_deinit(SPI0);
//    spi_struct_para_init(&spi_init_struct);

//    /* SPI0 parameter config */
//    spi_init_struct.trans_mode           = SPI_TRANSMODE_FULLDUPLEX;
//    spi_init_struct.device_mode          = SPI_MASTER;
//    spi_init_struct.frame_size           = SPI_FRAMESIZE_8BIT;
//    spi_init_struct.clock_polarity_phase = SPI_CK_PL_HIGH_PH_2EDGE;
//    spi_init_struct.nss                  = SPI_NSS_SOFT;
//		
//		
//		if (SystemCoreClock == 120000000)
//		{	//因为CPU规定的最高SPI频率为30M，所以/4
//			spi_init_struct.prescale             = SPI_PSC_4;
//		}
//		else
//		{
//			spi_init_struct.prescale             = SPI_PSC_2;
//		}
//    
//		
//    spi_init_struct.endian               = SPI_ENDIAN_MSB;
//    spi_init(SPI0, &spi_init_struct);
//    /* set crc polynomial */
////    spi_crc_polynomial_set(SPI0,7);
//	  spi_enable(SPI0);
//}



//================================================================================
// 函数名称：uint8_t Flash_WriteRegister(void)
// 功能描述：写FLASH寄存器
// 参数描述：
//================================================================================
void Flash_WriteRegister(uint8_t Reg1_cmd,uint8_t Reg2_cmd)
{

	FLASH_CS_L;
	SPI1_Byte(Write_Status_Reg);
	SPI1_Byte(Reg1_cmd);
	SPI1_Byte(Reg2_cmd);
	
	FLASH_CS_H;

}

//================================================================================
// 函数名称：uint8_t Flash_write_enable(void)
// 功能描述：取消FLASH写保护
// 参数描述：成功返回1，否则，返回0
//================================================================================
void Flash_write_enable(void)
{
Check:	 if(((Flash_Read_Reg(Read_Status_Reg1)) & Write_Enable_Bit) != Write_Enable_Bit)
		 {	 
			 Flash_Send_Cmd(Write_Enable);
			 while((Flash_Read_Reg(Read_Status_Reg1) & Busy_Bit) == Busy_Bit);	
			 goto Check;
		 }
}

//================================================================================
// 函数名称：uint8_t Flash_write_disable(void)
// 功能描述：打开FLASH写保护
// 参数描述：成功返回1，否则，返回0
//================================================================================
void Flash_write_disable(void)
{
Check1:	 if(((Flash_Read_Reg(Read_Status_Reg1)) & Write_Enable_Bit) == Write_Enable_Bit)
		 {	 
			 Flash_Send_Cmd(Write_Disable);
			 while((Flash_Read_Reg(Read_Status_Reg1) & Busy_Bit) == Busy_Bit);	
			 goto Check1;
		 } 
}

//================================================================================
// 函数名称：static uint8_t SPI0_Byte(uint8_t byte)
// 功能描述：SPI2发送/读取一字节数据
// 参数描述：无
//================================================================================
//uint8_t SPI0_Byte(uint8_t byte)
//{
//    /* loop while data register in not emplty */
//    while (RESET == spi_i2s_flag_get(SPI0,SPI_FLAG_TBE));

//    /* send byte through the SPI0 peripheral */
//    spi_i2s_data_transmit(SPI0,byte);

//    /* wait to receive a byte */
//    while(RESET == spi_i2s_flag_get(SPI0,SPI_FLAG_RBNE));

//    /* return the byte read from the SPI bus */
//    return(spi_i2s_data_receive(SPI0));
//}

uint8_t SPI1_Byte(uint8_t byte)
{
  uint32_t cnt = 0;
	
	/* loop while data register in not emplty */
	while (RESET == spi_i2s_flag_get(SPI1,SPI_FLAG_TBE))
	{
		cnt++;
		if (cnt > maxWaitCnt) 
		{
			return 0xFF;
			//break;
		}
	}

	/* send byte through the SPI0 peripheral */
	spi_i2s_data_transmit(SPI1,byte);

	/* wait to receive a byte */
	cnt = 0;
	while(RESET == spi_i2s_flag_get(SPI1,SPI_FLAG_RBNE))
	{
		cnt++;
		if (cnt > maxWaitCnt) 
		{
			return 0xFF;
			//break;
		}
	}

	/* return the byte read from the SPI bus */
	return(spi_i2s_data_receive(SPI1));
}

//================================================================================
// 函数名称：void Flash_Send_Cmd(uint8_t cmd)
// 功能描述：向flash发送指令
// 参数描述：cmd--要发送的指令
//================================================================================
void Flash_Send_Cmd(uint8_t cmd)
{
	FLASH_CS_L;
	SPI1_Byte(cmd);
	FLASH_CS_H;
}

//================================================================================
// 函数名称：void Flash_Send_Dat(uint8_t dat)
// 功能描述：向flash发送一字节数据
// 参数描述：dat--要发送的数据
//================================================================================
void Flash_Send_Dat(uint8_t dat)
{	
	FLASH_CS_L;
	SPI1_Byte(dat);
	FLASH_CS_H;
}

//================================================================================
// 函数名称：void Flash_Write_Byte(uint32_t addr,uint8_t byte)
// 功能描述：向flash的指定地址写入一字节数据
// 参数描述：addr--起始地址
//           byte--要写入的数据
//================================================================================
void Flash_Write_Byte(uint32_t addr,uint8_t byte)
{
	Flash_Send_Cmd(Write_Enable);
	while((Flash_Read_Reg(Read_Status_Reg1) & Busy_Bit) == Busy_Bit);
	FLASH_CS_L;
	SPI1_Byte(Page_Program);
	if(flashmode_cf == 0)
	{
		SPI1_Byte(addr >> 24);
	}
	SPI1_Byte(addr >> 16);
	SPI1_Byte(addr >> 8);
	SPI1_Byte(addr);
	SPI1_Byte(byte);
	FLASH_CS_H;
	while((Flash_Read_Reg(Read_Status_Reg1) & Busy_Bit) == Busy_Bit);	
}

//================================================================================
// 函数名称：void Flash_Write_Data(uint32_t addr,uint8_t *buf,uint16_t lenth)
// 功能描述：将指定长度的数据包写入flash中
// 参数描述：addr--起始地址
//           *buf--要写入的数据
//           length--要写入的数据长度 
//================================================================================
void Flash_Write_Data(uint32_t addr,uint8_t *buf,uint16_t lenth)
{
	uint32_t addr1,addr2;
	uint16_t i=0,lenth1;
	uint32_t cnt;
	addr1=addr;
	addr2=addr1;
	while(i<lenth)
	{
		lenth1=((256-addr1%256)<(lenth-i))?(256-addr1%256):(lenth-i);
		addr2=addr1+lenth1;
		Flash_Send_Cmd(Write_Enable);
		
		cnt = 0;
		while((Flash_Read_Reg(Read_Status_Reg1) & Busy_Bit) == Busy_Bit)
		{
			cnt++;
			if (cnt > maxWaitCnt)
			{
				return;
			}
		}
		FLASH_CS_L;
		SPI1_Byte(Page_Program);

		if(flashmode_cf == 0)
		{
			SPI1_Byte(addr1 >> 24);
		}
		SPI1_Byte(addr1 >> 16);
		SPI1_Byte(addr1 >> 8);
		SPI1_Byte(addr1);
		while(lenth1 --)
		{
			SPI1_Byte(*buf ++);
			i++;
		}
		FLASH_CS_H;
		cnt = 0;
		while((Flash_Read_Reg(Read_Status_Reg1) & Busy_Bit) == Busy_Bit)
		{
		cnt++;
			if (cnt > maxWaitCnt)
			{
				return;
			}
		}
		addr1=addr2;
	}
	Flash_write_disable();
}



//================================================================================
// 函数名称：uint8_t Flash_Read_Reg(uint8_t cmd)
// 功能描述：读取flash控制寄存器的内容，返回读取的结果
// 参数描述：cmd--读寄存器指令
//================================================================================
uint8_t Flash_Read_Reg(uint8_t cmd)
{
	uint8_t rbyte;
	FLASH_CS_L;
	SPI1_Byte(cmd); 
	rbyte = SPI1_Byte(0xff);
	FLASH_CS_H;

	return rbyte;
}



//================================================================================
// 函数名称：uint8_t Flash_Read_Byte(uint32_t addr)
// 功能描述：从flash中读取一字节数据
// 参数描述：addr--起始地址
//================================================================================
uint8_t Flash_Read_Byte(uint32_t addr)
{
	uint8_t data;
	FLASH_CS_L;
	SPI1_Byte(Read_Data);

	if(flashmode_cf == 0)
	{
		SPI1_Byte(addr >> 24);
	}

	SPI1_Byte(addr >> 16);
	SPI1_Byte(addr >> 8);
	SPI1_Byte(addr);
	data = SPI1_Byte(0xff);
	FLASH_CS_H;
	return data;
}
//================================================================================
// 函数名称：void Flash_Read_Data(uint32_t addr,uint8_t *buf,uint16_t lenth)
// 功能描述：从flash的指定地址处读出指定长度的数据
// 参数描述：addr--起始地址
//           *buf--读出数据的缓存区
//           length--要读出的数据长度
//================================================================================
void Flash_Read_Data(uint32_t addr,uint8_t *buf,uint16_t lenth)
{

	FLASH_CS_L;
	SPI1_Byte(Read_Data);

	if(flashmode_cf == 0)
	{
		SPI1_Byte(addr >> 24);
	}

	SPI1_Byte(addr >> 16);
	SPI1_Byte(addr >> 8);
	SPI1_Byte(addr);
	while(lenth --)
	{
		*buf ++ = SPI1_Byte(0xff);
	}
	FLASH_CS_H;
	
}




//================================================================================
// 函数名称：void Flash_Erase(uint8_t cmd,uint32_t addr)
// 功能描述：flash的块擦除升序
// 参数描述：cmd--擦除指令：4K、32K、64K
//           addr--起始地址
//           搽除失败
//================================================================================
void Flash_Erase(uint8_t cmd,uint32_t addr)                  //After the Erase cycle has finished the Write Enable Latch (WEL) bit is cleared to 0.
{
	uint16_t i;
	uint32_t cnt = 0;
	uint8_t f_buff[100];
	Flash_Send_Cmd(Write_Enable);
	while((Flash_Read_Reg(Read_Status_Reg1) & Busy_Bit) == Busy_Bit)
	{
		cnt ++;
		if (cnt > maxWaitCnt)
		{
			return;
		}
	}
	
	FLASH_CS_L;
	SPI1_Byte(cmd);

	if(flashmode_cf == 0)
	{
		SPI1_Byte(addr >> 24);
	}

	SPI1_Byte(addr >> 16);
	SPI1_Byte(addr >> 8);
	SPI1_Byte(addr);
	FLASH_CS_H;
	
	cnt = 0;
	while((Flash_Read_Reg(Read_Status_Reg1) & Busy_Bit) == Busy_Bit)
	{
		cnt ++;
		if (cnt > maxWaitCnt)
		{
			return;
		}
	}
	
	//加入搽除检验，搽除后，读取搽除后的头1K字节，如果均为FF，则成功
	Flash_Read_Data(addr,f_buff,100);
	for(i=0;(i<100)&&(f_buff[i]==0xff);i++);
	if(i<100)                                               //上次搽除失败，再次执行搽除指令
	{
		Flash_Send_Cmd(Write_Enable);
		
		cnt = 0;
		while((Flash_Read_Reg(Read_Status_Reg1) & Busy_Bit) == Busy_Bit)
		{
			cnt ++;
			if (cnt > maxWaitCnt)
			{
				return;
			}
		}
		
		FLASH_CS_L;
		SPI1_Byte(cmd);

		if(flashmode_cf == 0)
		{
			SPI1_Byte(addr >> 24);
		}

		SPI1_Byte(addr >> 16);
		SPI1_Byte(addr >> 8);
		SPI1_Byte(addr);
		FLASH_CS_H;
		
		cnt = 0;
		while((Flash_Read_Reg(Read_Status_Reg1) & Busy_Bit) == Busy_Bit)
		{
			cnt ++;
			if (cnt > maxWaitCnt)
			{
				return;
			}
		}
	}		
}


void Flash_EraseAll(uint8_t cmd)                  //After the Erase cycle has finished the Write Enable Latch (WEL) bit is cleared to 0.
{
	uint16_t i;
	uint8_t f_buff[1000];
	Flash_Send_Cmd(Write_Enable);
	while((Flash_Read_Reg(Read_Status_Reg1) & Busy_Bit) == Busy_Bit);
	FLASH_CS_L;
	SPI1_Byte(cmd);

	FLASH_CS_H;
	while((Flash_Read_Reg(Read_Status_Reg1) & Busy_Bit) == Busy_Bit);
	//加入搽除检验，搽除后，读取搽除后的头1K字节，如果均为FF，则成功
	Flash_Read_Data(0,f_buff,1000);
	for(i=0;(i<1000)&&(f_buff[i]==0xff);i++);
	if(i<1000)                                               //上次搽除失败，再次执行搽除指令
	{
		Flash_Send_Cmd(Write_Enable);
		while((Flash_Read_Reg(Read_Status_Reg1) & Busy_Bit) == Busy_Bit);
		FLASH_CS_L;
		SPI1_Byte(cmd);
		FLASH_CS_H;
		while((Flash_Read_Reg(Read_Status_Reg1) & Busy_Bit) == Busy_Bit);
	}		
}



//================================================================================
// 函数名称：void Flash_Init(void)
// 功能描述：flash初始化
// 参数描述：无
// 返回0代表初始化成功
// 返回1代表失败
//================================================================================
uint8_t Flash_Busy(void)
{
	uint32_t i = 0;
	uint32_t cntDly = 0;
	while(i < 500)
	{
		if((Flash_Read_Reg(Read_Status_Reg1) & Busy_Bit) != Busy_Bit)
		{
			return 0; 
		}
		else 
		{
			i ++;
			cntDly = 0;
			while(cntDly < 5000)
			{
				cntDly++;
			}
			
		} 	
	}
	return 1;
}



//flash id 验证；
//private
uint8_t verifyFlashID(void)
{
	uint8_t i = 0;
	uint16_t data = 0;
	FLASH_CS_L;
	for(i = 0;i < 3;i++)//最多读取三次
	{
		SPI1_Byte(0x90);
		SPI1_Byte(0x00);
		SPI1_Byte(0x00);
		SPI1_Byte(0x00);
		data |= SPI1_Byte(0xff) << 8;
		data |= SPI1_Byte(0xff);
		if ( ((data&0xff) == (W25Q16_ID&0xff)) ||
			((data&0xff) == (W25Q32_ID&0xff)) ||
			((data&0xff) == (W25Q64_ID&0xff)) ||
			((data&0xff) == (W25Q80_ID&0xff)))
		{
			break;
		}
	}
	FLASH_CS_H;	
	
	if(i < 3)
	{
		return (data&0xff);
	}
	else
	{
		return 0;
	}
}
//public
uint8_t getFlashID(void)
{
	return (verifyFlashID());
}


//================================================================================
// 函数名称：uint8_t Flash_Init(void)
// 功能描述：falsh初始化
// 参数描述：
// 返回0代表初始化成功
// 返回1代表失败
//================================================================================
uint8_t Flash_Init(void)														  
{
	uint8_t reDa = 0;
	
	//SPI0_Configuration();	
	SPI1_Configuration();	


	if(Flash_Busy() == 0)
	{
		if(((Flash_Read_Reg(Read_Status_Reg1)) & Write_Enable_Bit) != Write_Enable_Bit)
		{	 
			Flash_Send_Cmd(Write_Enable);
			while((Flash_Read_Reg(Read_Status_Reg1) & Busy_Bit) == Busy_Bit);	
		}
		reDa |= 0x01;
	}


	//判断是否4字节地址的Flash
	if(getFlashID() == (W25Q256_ID&0xff))
	{
		//进入四字节地址模式
		flashmode_cf = 0;
		
		if(Flash_Busy() == 0)
		{
			if(((Flash_Read_Reg(0x15)) & 0x01) != 0x01)
			{	 
				Flash_Send_Cmd(0xB7);
				while((Flash_Read_Reg(Read_Status_Reg1) & Busy_Bit) == Busy_Bit);	
			}
		}
	}
	else	
	{
		//3字节模式
		flashmode_cf = 1;
		
		//进入3字节模式
		if(Flash_Busy() == 0)
		{
			if(((Flash_Read_Reg(0x15)) & 0x01) != 0x00)	//GD25Q64C不支持该位
			{	 
				Flash_Send_Cmd(0xE9);
				while((Flash_Read_Reg(Read_Status_Reg1) & Busy_Bit) == Busy_Bit);	
			}
		}
		
	}
	
	if (reDa != 0x01)
	{
		return 1;
	}
	
	return 0; 
}











